﻿
using Xacml.Core;
using Xacml.Core.Interfaces;
using Xacml.Core.Policy;
using System;
using System.Collections;

namespace Xacml.Core.Runtime
{
  public class Condition2 : Condition, IEvaluable
  {
    public Condition2(ConditionElement condition)
      : base(condition)
    {
    }

    public override EvaluationValue Evaluate(EvaluationContext context)
    {
      context.Trace("Evaluating condition");
      context.AddIndent();
      try
      {
        foreach (IExpression expression in (CollectionBase) this.ApplyDefinition.Arguments)
        {
          if (expression is ApplyElement)
          {
            context.Trace("Apply within condition.");
            return new Apply((ApplyElement) expression).Evaluate(context);
          }
          if (expression is FunctionElementReadWrite)
            throw new NotImplementedException("pol.FunctionElement");
          if (expression is VariableReferenceElement)
          {
            VariableReferenceElement referenceElement = expression as VariableReferenceElement;
            VariableDefinition variableDefinition = context.CurrentPolicy.VariableDefinition[(object) referenceElement.VariableId] as VariableDefinition;
            if (!variableDefinition.IsEvaluated)
              return variableDefinition.Evaluate(context);
            return variableDefinition.Value;
          }
          if (expression is AttributeValueElementReadWrite)
          {
            context.Trace("Attribute value {0}", (object) expression.ToString());
            AttributeValueElement attributeValueElement = new AttributeValueElement(((AttributeValueElementReadWrite) expression).DataType, ((AttributeValueElementReadWrite) expression).Contents, ((XacmlElement) expression).SchemaVersion);
            return new EvaluationValue(attributeValueElement.GetTypedValue(attributeValueElement.GetType(context), 0), attributeValueElement.GetType(context));
          }
          if (expression is AttributeDesignatorBase)
          {
            context.Trace("Processing attribute designator: {0}", (object) expression.ToString());
            AttributeDesignatorBase attributeDesignatorBase = (AttributeDesignatorBase) expression;
            BagValue bagValue = new BagValue(context.Engine.GetDataType(attributeDesignatorBase.DataType));
            return new EvaluationValue((object) bagValue, bagValue.GetType(context));
          }
          if (expression is AttributeSelectorElement)
          {
            context.Trace("Attribute selector");
            AttributeSelectorElement attributeSelectorElement = (AttributeSelectorElement) expression;
            BagValue bagValue = new BagValue(context.Engine.GetDataType(attributeSelectorElement.DataType));
            return new EvaluationValue((object) bagValue, bagValue.GetType(context));
          }
        }
        throw new NotSupportedException("internal error");
      }
      finally
      {
        context.TraceContextValues();
        context.RemoveIndent();
      }
    }
  }
}
